package name.cyl.parseXml.y121120;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public final class ParseXmlServices {
    private static final SAXParserFactory SAX_PARSER_FACTORY = SAXParserFactory.newInstance();

    public static final Map<String, List<Map<String, String>>> parseXmlToMap(InputStream inputStream) {
        try {
            SAXParser saxParser = SAX_PARSER_FACTORY.newSAXParser();
            Map<String, List<Map<String, String>>> map = new HashMap<String, List<Map<String, String>>>();
            saxParser.parse(inputStream, new XmlToMapHandler(map));
            return map;
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

final class XmlToMapHandler extends DefaultHandler {
    private final LinkedList<Object> stack = new LinkedList<Object>();
    private final Map<String, List<Map<String, String>>> resultMap;

    public XmlToMapHandler(Map<String, List<Map<String, String>>> map) {
        resultMap = map;
    }

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }

    @SuppressWarnings("unchecked")
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        switch (stack.size()) {
        case 0:
            stack.push(resultMap);
            break;
        case 1: {
            Map<String, List<Map<String, String>>> resultMap = (Map<String, List<Map<String, String>>>) stack.peek();
            List<Map<String, String>> list = new ArrayList<Map<String, String>>();
            resultMap.put(qName, list);
            stack.push(list);
        }
            break;
        case 2:
            List<Map<String, String>> list=(List<Map<String, String>>) stack.peek();
            Map<String, String> record=new HashMap<String, String>();
            list.add(record);
            for(int i=0;i<attributes.getLength();i+=1){
                record.put(attributes.getQName(i), attributes.getValue(i));
            }
            stack.push(record);
            break;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        switch (stack.size()) {
        case 1:
            stack.pop();
            break;
        case 2:
            stack.pop();
            break;
        case 3:
            stack.pop();
            break;
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
    }

    @Override
    public void error(SAXParseException e) throws SAXException {
        e.printStackTrace();
    }

    @Override
    public void fatalError(SAXParseException e) throws SAXException {
        e.printStackTrace();
    }

}